﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using PhoneMap.ViewModel;
using System.Text.RegularExpressions;
using PhoneMap.Common;
using System.Threading.Tasks;
using System.IO;
using System.Runtime.Serialization.Json;
using System.Text;
using PhoneMap.Model;
using Windows.Devices.Geolocation;
using System.Device.Location;

namespace PhoneMap.View
{
    public partial class Login : PhoneApplicationPage
    {
        LoginViewModel login;
        WebBrowser web;

        public Login()
        {
            InitializeComponent();
            login = new LoginViewModel();
            DataContext = login;

        }

        private void CheckExitsWebFb()
        {
            if (ParentRoot.Children.Contains(web))
                ParentRoot.Children.Remove(web);
        }
        protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
        {
            if (ParentRoot.Children.Contains(web))
            {
                e.Cancel = true;
                CheckExitsWebFb();
                return;
            }
            else
                e.Cancel = false;
        }
        private void Button_Click(object sender, RoutedEventArgs e)
        {

            CheckExitsWebFb();
            web = new WebBrowser();
            web.Navigated += WebBrowser_Navigated;
            web.NavigationFailed += web_NavigationFailed;
            web.Source = new Uri(GetLoginUrl());
            ParentRoot.Children.Add(web);
        }

        private void web_NavigationFailed(object sender, NavigationFailedEventArgs e)
        {
            ParentRoot.Children.Remove(web);
            MessageBox.Show("Login với Facebook bị lỗi, xin kiểm tra lại mạng hoặc kết nối internet.");

        }

        private void WebBrowser_Navigated(object sender, NavigationEventArgs e)
        {
            String uri = e.Uri.ToString();

            if (uri.StartsWith("https://www.facebook.com/connect/login_success.html") || uri.StartsWith("http://www.facebook.com/connect/login_success.html"))
            {
                // Remove junk text added by facebook from url
                if (uri.EndsWith("#_=_"))
                    uri = uri.Substring(0, uri.Length - 4);


                String queryString = e.Uri.Query.ToString();

                // Acquire the code from Query String
                IEnumerable<KeyValuePair<string, string>> pairs = UriToolKits.ParseQueryString(queryString);
                string code = KeyValuePairUtils.GetValue(pairs, "code");

                // Get access_token from code using Asynchronous HTTP Request
                WebClient client = new WebClient();
                client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(AccessTokenDownloadCompleted);
                client.DownloadStringAsync(new Uri(GetAccessTokenRequestUrl(code)));
            }
        }

        private void AccessTokenDownloadCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            CheckExitsWebFb();
            if (e.Cancelled)
                return;
            if (e.Error != null)
            {
                MessageBox.Show("Error Occurred: " + e.Error.Message);
                return;
            }

            string data = e.Result;
            data = "?" + data;

            // Acquire access_token and expires timestamp
            IEnumerable<KeyValuePair<string, string>> pairs = UriToolKits.ParseQueryString(data);
            string accessToken = KeyValuePairUtils.GetValue(pairs, "access_token");
            string expires = KeyValuePairUtils.GetValue(pairs, "expires");
            UserSetting.Instance.SaveTokenFbData(accessToken);
            // Get access_token from code using Asynchronous HTTP Request
            WebClient client = new WebClient();
            client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(UserProfileAccess);
            client.DownloadStringAsync(new Uri(GetUserProfileURL(accessToken)));


            WebClient clients = new WebClient();
            clients.DownloadStringCompleted += new DownloadStringCompletedEventHandler(GetListFriends);
            clients.DownloadStringAsync(new Uri(GetListFriendsURL(accessToken)));
        }

        private async void GetListFriends(object sender, DownloadStringCompletedEventArgs e)
        {
            if (e.Cancelled)
                return;
            if (e.Error != null)
            {
                MessageBox.Show("Error Occurred: " + e.Error.Message);
                return;
            }
            try
            {

                var getData = await DataParser.DoGetJonAsync<FriendsFacebooks>(e.Result.ToString());

                if (getData != null)
                {
                    await StorageProvider.SaveObjectsAsync<FriendsFacebooks>(getData, StorageProvider.LISTFRIENDS);
                }
            }
            catch (InvalidOperationException ex)
            {
                string message = "Login failed! Exception details: " + ex.Message;
                MessageBox.Show(message);
            }
        }

        private async void UserProfileAccess(object sender, DownloadStringCompletedEventArgs e)
        {
            if (e.Cancelled)
                return;
            if (e.Error != null)
            {
                MessageBox.Show("Error Occurred: " + e.Error.Message);
                return;
            }
            try
            {

                var getData = await DataParser.DoGetJonAsync<FacebookData>(e.Result.ToString());

                if (getData != null)
                {
                    await StorageProvider.SaveObjectsAsync<FacebookData>(getData, StorageProvider.FACEBOOKDATA);
                    login.Login(getData);
                    this.IsHitTestVisible = true;
                }
            }
            catch (InvalidOperationException ex)
            {
                string message = "Login failed! Exception details: " + ex.Message;
                MessageBox.Show(message);
            }
        }

        public virtual String GetLoginUrl()
        {
            return "https://facebook.com/dialog/oauth?client_id=" + App.FacebookAppID + "&redirect_uri=https://www.facebook.com/connect/login_success.html&scope=" + App.Scope + "&display=touch";
        }
        public virtual String GetAccessTokenRequestUrl(string code)
        {
            return "https://graph.facebook.com/oauth/access_token?client_id=" + App.FacebookAppID + "&redirect_uri=https://www.facebook.com/connect/login_success.html&client_secret=" + App.ClientSecret + "&code=" + code;
        }
        public virtual String GetUserProfileURL(string accessToken)
        {
            return "https://graph.facebook.com/me?access_token=" + accessToken;
        }
        public virtual String GetListFriendsURL(string accessToken)
        {
            return "https://graph.facebook.com/me/friends?access_token=" + accessToken;
        }
    }
    public static class KeyValuePairUtils
    {
        public static TValue GetValue<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> pairs, TKey key)
        {
            foreach (KeyValuePair<TKey, TValue> pair in pairs)
            {
                if (key.Equals(pair.Key))
                    return pair.Value;
            }

            throw new Exception("the value is not found in the dictionary");
        }
    }
    public static class UriToolKits
    {
        private static readonly Regex QueryStringRegex = new Regex(@"[\?&](?<name>[^&=]+)=(?<value>[^&=]+)");

        public static IEnumerable<KeyValuePair<string, string>> ParseQueryString(this string uri)
        {
            if (uri == null)
                throw new ArgumentException("uri");

            var matches = QueryStringRegex.Matches(uri);
            for (var i = 0; i < matches.Count; i++)
            {
                var match = matches[i];
                yield return new KeyValuePair<string, string>(match.Groups["name"].Value, match.Groups["value"].Value);
            }
        }
    }
}